﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Common;
using HerGoS.Interfaces;

namespace HerGoS.DAO
{
    public class RepositoryFactory
    {
        static IDictionary<string, string> connections = new Dictionary<string, string>();

        //Lista de reposotorios transaccionales en session
        static List<IRepository> Repositories
        {
            get
            {
                if (HttpHelper.Session<List<IRepository>>("RepositoriesTransList") == null)
                    HttpHelper.StoreInSession("RepositoriesTransList", new List<IRepository>());

                return HttpHelper.Session<List<IRepository>>("RepositoriesTransList");
            }
        }

        /// <summary>
        /// Agrega una nueva conexión
        /// </summary>
        /// <param name="name">Nombre de la conexión</param>
        /// <param name="connectionstring">Cadena de conexión</param>
        public static void AddConnection(string name, string connectionstring)
        {
            connections.Add(name, connectionstring);
        }
        /// <summary>
        /// Elimina una conexión
        /// </summary>
        /// <param name="name">Nombre de la conexión</param>
        public static void RemoveConnection(string name)
        {
            connections.Remove(name);
        }
        /// <summary>
        /// Obtiene la cadena de conexión mediante su nombre
        /// </summary>
        /// <param name="name">Nombre de la conexión</param>
        /// <returns>Cadena de conexión</returns>
        public static string GetConnection(string name)
        {
            string value = "";
            if (connections.ContainsKey(name))
                value = connections[name];
            return value;
        }
        /// <summary>
        /// Obtiene la cadena de conexión mediante su nombre cambiando el nombre del repositorio por el indicado
        /// </summary>
        /// <param name="name">Nombre de la conexión</param>
        /// <param name="dbname">Nombre del repositorio</param>
        /// <returns>Cadena de conexión</returns>
        public static string GetConnection(string name, string dbname)
        {
            string value = "";
            if (connections.ContainsKey(name))
            {
                value = connections[name];
                DbConnectionStringBuilder builder = new DbConnectionStringBuilder();
                builder.ConnectionString = value;
                builder.Add("Initial Catalog", dbname);
                value = builder.ConnectionString;
            }
            return value;
        }
        /// <summary>
        /// Crea el objeto de conexión al repositorio
        /// </summary>
        /// <param name="NameOrConnectionString">Nombre de la conexión o el ConnectionString</param>
        /// <returns>Objeto de conexión</returns>
        public static IRepository Create(string NameOrConnectionString)
        {
            CheckDisposed();
            string cs = GetConnection(NameOrConnectionString);
            if (cs == "") cs = NameOrConnectionString;
            RepositorySql sp = new RepositorySql(cs);
            return sp;        
        }
        /// <summary>
        /// Crea el objeto de conexión al repositorio transaccional
        /// </summary>
        /// <param name="NameOrConnectionString">Nombre de la conexión o el ConnectionString</param>
        /// <returns>Objeto de conexión</returns>
        public static IRepository CreateTransactional(string NameOrConnectionString)
        {
            CheckDisposed();
            string cs = GetConnection(NameOrConnectionString);
            if (cs == "") cs = NameOrConnectionString;
            RepositorySql sp = new RepositorySql(cs);
            sp.BeginTransaction();            
            //sp.OnRollback += new EventHandler(sp_OnRollback);
            //sp.OnCommit += new EventHandler(sp_OnCommit);
            //Repositories.Add(sp);
            return sp;
        }
        /// <summary>
        /// Crea el objeto de conexión al repositorio
        /// </summary>
        /// <param name="name">Nombre de la conexión</param>
        /// <param name="dbname">Nombre del repositorio</param>
        /// <returns>Objeto de conexión</returns>
        public static IRepository Create(string name, string dbname)
        {
            CheckDisposed();
            string cs = GetConnection(name, dbname);
            RepositorySql sp = new RepositorySql(cs);
            return sp;
        }
        /// <summary>
        /// Crea el objeto de conexión al repositorio transaccional
        /// </summary>
        /// <param name="name">Nombre de la conexión</param>
        /// <param name="dbname">Nombre del repositorio</param>
        /// <returns>Objeto de conexión</returns>
        public static IRepository CreateTransactional(string name, string dbname)
        {
            CheckDisposed();
            string cs = GetConnection(name, dbname);
            RepositorySql sp = new RepositorySql(cs);
            sp.BeginTransaction();
            //sp.OnRollback += new EventHandler(sp_OnRollback);
            //sp.OnCommit += new EventHandler(sp_OnCommit);
            //Repositories.Add(sp);
            return sp;
        }

        static void sp_OnCommit(object sender, EventArgs e)
        {
            DbTransaction tx = ((IRepository)sender).GetTransaction();
            if (tx == Repositories.FirstOrDefault().GetTransaction())
            {
                foreach (IRepository repo in Repositories)
                {
                    try
                    {
                        repo.GetTransaction().Commit();
                        repo.GetTransaction().Dispose();
                        repo.CerrarConexion();
                    }
                    catch (Exception)
                    {
                    }
                }
                Repositories.Clear();
            }
        }

        static void sp_OnRollback(object sender, EventArgs e)
        {
            //Hace roolbak de toda la lista
            foreach (IRepository repo in Repositories.Reverse<IRepository>())
            {
                try
                {
                    repo.GetTransaction().Rollback();
                    repo.GetTransaction().Dispose();
                    repo.CerrarConexion();
                }
                catch (Exception)
                {
                }
                Repositories.Clear();

            }
        }

        private static void CheckDisposed()
        {

        }
    }
}
